// Feature Test Entry
// UTF-8
//TODO trim!!
Html5Test= {}

Html5Test.Strap = function(conf){
	this.configLoaded = false;
	this.ok = false;
	this.observer = conf.ob;
	this.container = conf.container;
	this.sandBox = conf.sandBox;

	this.scripts = {
		total: 	0,
		loaded: 0,
		list: 	{}
	};
	this.categories = {
		total:	0,
		nameList: []/*,
		list:	{}*/
	};

	this.modules = {
		total:	0,
		list: 	[]
	};
	this.loadConfig("./config.xml");
}

Html5Test.Strap.prototype.ready = function()
{
	if (this.configLoaded && this.scripts.total == this.scripts.loaded)
	{
		if (!this.ok) {
			this.ok = true;
			this.observer.finish();
		}
		return true;
	}
	else return false;
}

Html5Test.Strap.prototype.updateReadyState = function()
{
	if (this.ready()) 
	{
		//$('#loadStatus p').append("Test Module Loading Complete.<br/>");
		this.fullTest();
	}
}

Html5Test.Strap.prototype.fullTest = function() {
	if (this.ready())
	{
		//$('#loadStatus p').append("Full test start.<br/>");
		for (var i = 0; i < this.modules.total; i++)
		{
			this.testModule(this.modules.list[i]);
		}
	}
	else alert("Script not fully loaded.");
}

Html5Test.Strap.prototype.testModule = function(module)
{
	var ret;
	this.sandBox.innerHTML = "";
	var c_name = module.categoryName;
	var container;
	if (c_name)
	{
		if (!document.getElementById(c_name))
		{
			var c_div = document.createElement("div");
			c_div.className = "cat";
			c_div.id = c_name;
			c_div.innerHTML = "<p class=cat_title>"+c_name+"</p>";
			this.container.appendChild(c_div);
		}
		container = document.getElementById(c_name);
	}
	else {
		container = this.container;
	}
	if (module.method != '') 
	{
		if (module.mode == "active") ret = eval(module.method+"("+module.param+")");
		else if (module.mode == "positive") {
		}
		node = document.createElement("div");
		mod_title = document.createElement("div");
		tbl = document.createElement("table");
		node.className = "mod";
		mod_title.className = "mod_title";
		mod_title.onclick = function(){
			$("#" + this.innerHTML).toggle();
		}
		mod_title.innerHTML = module.moduleName;
		tbl.id = module.moduleName;
		node.appendChild(mod_title);
		node.appendChild(tbl);
		this.parseResult(ret.nlist, tbl, true);
		container.appendChild(node);
	}
}

Html5Test.Strap.prototype.parseResult = function(list, node, list_mark)
{
	if (list_mark == false)
	{
		var tbl = document.createElement("table");
		tbl.className = list.type;
		node.appendChild(tbl);
		if (tbl.className == 'compo')
		{
		}
		else if (tbl.className == "aggrg") 
		{
			var head = document.createElement("th");
			head.innerHTML = list.layerName;
			head.className = "subtitle";
			tbl.insertRow(tbl.rows.length).appendChild(head);
		}
		this.parseResult(list.nlist, tbl,true);
	}
	else {
		for (var prop in list)
		{
			var tr = node.insertRow(node.rows.length);
			if (Html5Test.Static.Utility.isObject(list[prop])) 
			{
				this.parseResult(list[prop], tr, false);
			}
			else {
				if (typeof(list[prop]) == 'boolean') {
					var td1 = tr.insertCell(tr.cells.length), td2 = tr.insertCell(tr.cells.length);
					td1.innerHTML = prop;
					td1.className = "item";
					td2.className = "result";
					if (list[prop]) {
						td2.innerHTML = "<img src='/html5feature/img/tick.png'>"; 
					}
					else {
						td2.innerHTML = "<img src='/html5feature/img/cross.png'>"; 
					}
				}
				//else {
					//td2.innerHTML = list[prop];
				//}
			}
		}
	}
}

Html5Test.Strap.prototype.loadModuleList = function(moduleList)
{
	this.observer.start("Load Modules From Files");
	for (var i = 0; i < moduleList.length; i++)
	{
		var id = this.loadModule(moduleList[i]);
		for (var j = 0; j < moduleList[i].src.length; j++)
			if (!this.isScriptLoaded(moduleList[i].src[j])) 
			{
				this.loadScript(moduleList[i].src[j]);
				this.appendModuleToScript(id, moduleList[i].src[j]);
			}

		if (!this.isCategoryExist(moduleList[i].categoryName))
			this.addCategory(moduleList[i].categoryName);
	}
	this.observer.end("Load Modules From Files");
}

Html5Test.Strap.prototype.loadModule = function(module)
{
	++this.modules.total;
	this.modules.list.push({
		moduleName: 	module.moduleName,
		method: 		module.method,
		param:			module.param,
		enableByDefault:module.enableByDefault,
		type:			module.type,
		mode:			module.mode,
		fileTBL:		module.src.length,
		fileLoaded:		0
	});
	if (module.categoryName != "")
		this.modules.list[this.modules.total-1].categoryName = module.categoryName;
	return this.modules.total - 1;
}

Html5Test.Strap.prototype.isCategoryExist = function(c_name)
{
	for (var i = 0; i < this.categories.nameList.length; i++)
		if (this.categories.nameList[i] == c_name)
			return true;
	return false;
}

Html5Test.Strap.prototype.addCategory = function(c_name)
{
	++this.categories.total;
	this.categories.nameList.push(c_name);
}

Html5Test.Strap.prototype.appendModuleToScript = function(m_id, src)
{
	this.scripts.list[src].modules.push(m_id);
}

Html5Test.Strap.prototype.isScriptLoaded = function(src)
{
	if (this.scripts.list[src]) return true;
	else return false;
}

Html5Test.Strap.prototype.loadScript = function(src)
{
	this.observer.addFileToLoad(src);
	++this.scripts.total;
	this.scripts.list[src] = {
		available: 	false,
		modules: 	[]
	}

	var index = src.lastIndexOf(".");
	var type = src.substr(index + 1, src.length - index);

	if (type == "js") {
		Html5Test.Static.Utility.dynamicJLoader(src, 
				function(CallBackConf){
					Html5Test.Static.getInstance().scriptReceiver(CallBackConf);
				});
	}
	else if (type == "css") {
		Html5Test.Static.Utility.dynamicCssLoader(src,
			function(CallBackConf){
				Html5Test.Static.getInstance().scriptReceiver(CallBackConf);
			});
	}
}

Html5Test.Strap.prototype.scriptReceiver = function(CallBackConf)
{
	++this.scripts.loaded;
	script = this.scripts.list[CallBackConf.src];
	script.available = true;
	for (var i = 0; i < script.modules.length; i++)
	{
		//TODO may implement visual effect when a test module is available
		++this.modules.list[script.modules[i]].fileLoaded;
	}
	this.observer.fileLoaded(CallBackConf.src);
	this.updateReadyState();
}

Html5Test.Strap.prototype.loadConfig = function(xmlSrc)
{
	this.observer.start("Load Test Config");
	Html5Test.Static.Utility.xmlLoader(xmlSrc, 
			function(xmlDom){
				Html5Test.Static.getInstance().confReceiver({
					xml: xmlDom
				});
			});
}

Html5Test.Strap.prototype.confReceiver = function(CallBackConf)
{
	this.configLoaded = true;
	this.observer.end("Load Test Config");
	this.loadModuleList(Html5Test.Static.Utility.parseConfig(CallBackConf.xml));
}

/*	----Observer----	*/

Html5Test.Observer = function(container)
{
	this.container = container;
	this.proc = document.createElement("div");
	this.proc.id = "proc";
	this.proc.innerHTML = "<p>Overall Progress</p>";
	this.file = document.createElement("div");
	this.file.id = "file";
	this.file.innerHTML = "<p>File Loading Status</p>";
	this.container.appendChild(this.proc);
	this.container.appendChild(this.file);
}

Html5Test.Observer.prototype.start = function(pname)
{
	var div = document.createElement("div");
	div.id = pname;
	div.className = "unload"
	div.innerHTML = pname; 
	this.proc.appendChild(div);
}

Html5Test.Observer.prototype.end = function(pname)
{
	var div = document.getElementById(pname);
	if (div) div.className = "load";
	else alert("Unregisterd process " + pname + "processed.");
}

Html5Test.Observer.prototype.finish = function(src)
{
	var div = document.createElement("div");
	div.id = "finish";
	div.className = "load";
	div.innerHTML = "Load Complete";
	this.proc.appendChild(div);
}

Html5Test.Observer.prototype.addFileToLoad = function(src)
{
	var div = document.createElement("div");
	var fileName = src.substr(src.lastIndexOf("/") + 1, src.length - src.lastIndexOf("/"));
	div.id = src;
	div.className = "unload";
	div.innerHTML = fileName;
	this.file.appendChild(div);
}

Html5Test.Observer.prototype.fileLoaded = function(src)
{
	var div = document.getElementById(src);
	if (div) div.className = "load";
	else alert("Unregistered file " + src + " loaded.");
}

/*	---Static----	*/
Html5Test.Static = {}

// create a new testFrame
Html5Test.Static.createTestFrame = function(test_container, load_container) {
	window.html5Feature = {};
	Html5Test.Static.fetchBrowserType();
	//window.html5Feature.ob = new Html5Test.Observer(document.getElementById("loadStatus"));
	window.html5Feature.ob = new Html5Test.Observer(load_container);
	window.html5Feature.testFrame = new Html5Test.Strap({
		ob: window.html5Feature.ob,
		container: test_container,
		sandBox: Html5Test.Static.getSandBox()
	});
}
// get the current testFrame
Html5Test.Static.getInstance = function() {
	if (!window.html5Feature || !window.html5Feature.testFrame) Html5Test.Static.createTestFrame();
	return window.html5Feature.testFrame;
}

Html5Test.Static.getSandBox = function() {
	return document.getElementById("sandbox");
}

Html5Test.Static.fetchBrowserType = function()
{
	var sys = {};
	var ua = navigator.userAgent.toLowerCase();
	var s;
	(s = ua.match(/msie ([\d.]+)/)) ? (sys.type="msie",sys.version=s[1]):
		(s = ua.match(/firefox\/([\d.]+)/)) ? (sys.type="firefox",sys.version=s[1]):
		(s = ua.match(/chrome\/([\d.]+)/)) ? (sys.type="chrome",sys.version=s[1]):
		(s = ua.match(/opera.([\d.]+)/)) ? (sys.type="opera",sys.version=s[1]):
		(s = ua.match(/version\/([\d.]+).*safari/)) ? (sys.type="opera",sys.version=s[1]): 
		(sys.type="unknown",sys.version=s[1]);

	window.html5Feature.browserType = sys;
	window.html5Feature.browserType.mainVersion = window.html5Feature.browserType.version.indexOf(".") != -1 ?
	   html5Feature.browserType.version.substr(0, window.html5Feature.browserType.version.indexOf(".")) : html5Feature.browserType.version;
	//window.html5Feature.browserType.verbose = navigator.userAgent.toLowerCase();
}

// auxilliary library
// might take into consideration compatibility on different OS
Html5Test.Static.Utility = {}


// might be changed
// load javascript
Html5Test.Static.Utility.dynamicJLoader = function(src, CALLBACK)
{
	$.ajax({
		url: src,
		type: "Get",
		dataType: "script",
		success: function() {
			CALLBACK({src:src});
		},
		error: function(jqXHR, textStatus, errorThrown){
			alert("Script " + src + " load error\n" + textStatus + " " + jqXHR.status + " " + errorThrown);
		}
	});
}

// load css 
Html5Test.Static.Utility.dynamicCssLoader = function(src, CALLBACK)
{
	var sheet, cssRules;
	var link = document.createElement("link");
	link.setAttribute("rel", "stylesheet");
	link.setAttribute("type", "text/css");
	link.setAttribute("href", src);
	document.getElementsByTagName("head")[0].appendChild(link);

	if (html5Feature.browserType.type == 'msie' /*|| html5Feature.browserType.type == 'opera'*/ || html5Feature.browserType.type == 'firefox')
	{
		link.onload = function(){
			CALLBACK({src: src});
		}
	}
	else {
		sheet = 'sheet'; cssRules = 'cssRules';
		var _timer1 = setInterval( function() { // check whether css loaded by timer
			try {
				if ( link[sheet] && link[sheet][cssRules].length ) { // might cross domain
					clearInterval(_timer1); 
					clearTimeout(_timer2);
					CALLBACK({src: src});
				}
			} catch( e ) {
				alert(e);
				clearInterval(_timer1); 
				clearTimeout(_timer2);
				// might not be completely loaded
				// cross Domain
			} finally {}
		}, 20 ),
			// loading timeout 10s 
			_timer2 = setTimeout( function() {
				clearInterval( _timer1 ); 
				clearTimeout( _timer2 );
				//error function
			}, 10000 );
	}
}

// load XML file
Html5Test.Static.Utility.xmlLoader = function(xmlSrc, CALLBACK) {
	$.ajax({
		url: xmlSrc,
	type: "GET",
	dataType: "xml",
	success: function(xmlData){
		CALLBACK(xmlData);
	},
	error: function(jqXHR, textStatus, errorThrown){
			   alert("XML Load Error\n" + textStatus + " " + jqXHR.status + " " + errorThrown);
		   }
	});
}

Html5Test.Static.Utility.parseConfig = function(xmlDom)
{
	var moduleList = [];
	for (var i = 0; i < $("module", xmlDom).length; i++)
	{
		modDom = $("module", xmlDom)[i];
		mod = {
			mode:			modDom.getAttribute("mode") ? modDom.getAttribute("mode") : "active",
			type:			modDom.getAttribute("type") ? modDom.getAttribute("type") : "js",
			moduleName: 	Html5Test.Static.Utility.getNodeText($("moduleName", modDom)[0]),
			categoryName: 	Html5Test.Static.Utility.getNodeText($("categoryName", modDom)[0]),
			src:			[],
			method: 		Html5Test.Static.Utility.getNodeText($("method", modDom)[0]),
			param:			Html5Test.Static.Utility.getNodeText($("param", modDom)[0]),
			enableByDefault: Html5Test.Static.Utility.getNodeText($("enableByDefault", modDom)[0])
		};

		for (var j = 0; j < $("src", modDom).length; j++)
		{
			mod.src.push(Html5Test.Static.Utility.getNodeText($("src", modDom)[j]));
		}

		if (mod.type == 'css') {
			mod.css = Html5Test.Static.Utility.getNodeText($("css", modDom)[0]);
		}
		moduleList.push(mod);
	}
	return moduleList;
}

Html5Test.Static.Utility.getNodeText = function(node)
{
	if (!node) return ""
		if (node.textContent) return node.textContent;
	if (node.text)	return node.text;
	return "";
}

Html5Test.Static.Utility.isArray = function(item)
{
	return Object.prototype.toString.call(item) == "[object Array]";
}

Html5Test.Static.Utility.isObject = function(item)
{
	return typeof(item) == "object";
}
